package com.qs.commontools.utils.file;

import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.qs.commontools.common.service.ImgService;
import com.qs.commontools.utils.base.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;

/**
 * 二维码操作类
 * @author qiusuo
 * @since 2021-11-14
 */
public class QRcodeTool implements Serializable {

    private static final long serialVersionUID = -7483376236905684805L;

    /**
     * 连接地址
     */
    private String hyperlink;

    /**
     * 编码
     */
    private String charset;

    /**
     * 后缀
     */
    private String suffix;

    /**
     * 二维码尺寸
     */
    private Integer size;

    /**
     * 二维码内部logo宽度
     */
    private Integer width;

    /**
     * 二维码内部logo高度
     */
    private Integer height;

    /**
     * 二维码中嵌入的logo
     */
    private File logo;

    /**
     * 是否需要压缩
     */
    private Boolean needCompress;

    /**
     * 纠错等级L/M/Q/H,纠错等级越高越不易识别，当前设置等级为最高等级H
     */
    private ErrorCorrectionLevel errorCorrectionLevel;

    /**
     * 设置空白处的大小
     */
    private Integer margin;


    private QRcodeTool() {
    }

    /**
     * 获得二维码操作实例对象。
     * @return 二维码操作实例对象
     */
    public static QRcodeTool getInstance(){
        QRcodeTool tool = new QRcodeTool();
        // 默认编码UTF-8
        tool.setCharset("UTF-8");
        // 默认图片后缀JPG
        tool.setSuffix("JPG");
        // 设置二维码默认尺寸为300
        tool.setSize(300);
        // 设置二维码内部logo默认宽度
        tool.setWidth(60);
        // 设置二维码内部logo默认高度
        tool.setHeight(60);
        // 设置纠错等级
        tool.setErrorCorrectionLevel("H");
        // 设置空白处大小
        tool.setMargin(1);
        // 默认嵌入logo需要压缩
        tool.setNeedCompress(true);
        return tool;
    }

    /**
     * 获得序列化号。
     *
     * @return 序列号
     */
    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    /**
     * 获得链接地址。
     *
     * @return 链接地址
     */
    public String getHyperlink() {
        return hyperlink;
    }

    /**
     * 设置链接地址。
     *
     * @param hyperlink 链接地址
     */
    public void setHyperlink(String hyperlink) {
        this.hyperlink = hyperlink;
    }

    /**
     * 获得编码。
     *
     * @return 编码
     */
    public String getCharset() {
        return charset;
    }

    /**
     * 设置编码，如"UTF-8"。
     *
     * @param charset 编码
     */
    public void setCharset(String charset) {
        this.charset = charset;
    }

    /**
     * 设置后缀，如"JPG"。
     *
     * @return 后缀
     */
    public String getSuffix() {
        return suffix;
    }

    /**
     * 获得后缀。
     *
     * @param suffix 后缀
     */
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    /**
     * 获得二维码的尺寸，二维码整个外边框的长宽，默认300。
     *
     * @return 尺寸
     */
    public Integer getSize() {
        return size;
    }

    /**
     * 设置二维码外面整体的尺寸，默认300。
     *
     * @param size 尺寸
     */
    public void setSize(Integer size) {
        this.size = size;
    }

    /**
     * 获得二维码内部logo的宽度，默认60。
     *
     * @return 二维码内部logo的宽度
     */
    public Integer getWidth() {
        return width;
    }

    /**
     * 设置二维码内部logo的宽度，默认60。
     *
     * @param width 二维码内部logo的宽度
     */
    public void setWidth(Integer width) {
        this.width = width;
    }

    /**
     * 获得二维码内部logo的高度，默认60。
     *
     * @return 二维码内部logo的高度
     */
    public Integer getHeight() {
        return height;
    }


    /**
     * 设置二维码内部logo的高度，默认60。
     *
     * @param height 二维码内部logo的高度
     */
    public void setHeight(Integer height) {
        this.height = height;
    }

    /**
     * 获取二维码内部的logo图片File对象。
     *
     * @return logo图片File对象
     */
    public File getLogo() {
        return logo;
    }

    /**
     * 通过图片File对象设置二维码内部的logo图片。
     *
     * @param logo 图片File对象
     */
    public void setLogo(File logo) {
        this.logo = logo;
    }

    /**
     * 通过图片地址设置二维码内部的logo图片。
     *
     * @param logo 图片地址
     */
    public void setLogo(String logo) {
        setLogo(new File(logo));
    }

    /**
     * 获取是否需要压缩logo图片，默认需要压缩。
     *
     * @return 是否需要压缩图片，true需要，false不需要
     */
    public Boolean getNeedCompress() {
        return needCompress;
    }

    /**
     * 设置是否需要压缩logo图片，默认需要压缩。
     * @param needCompress true需要，false不需要
     */
    public void setNeedCompress(Boolean needCompress) {
        this.needCompress = needCompress;
    }

    /**
     * 获取纠错等级L/M/Q/H,纠错等级越高越不易识别，默认设置等级为最高等级H。
     *
     * @return 获得纠错等级ErrorCorrectionLevel对象
     */
    public ErrorCorrectionLevel getErrorCorrectionLevel() {
        return errorCorrectionLevel;
    }

    /**
     * 获取纠错等级L/M/Q/H枚举类型的值。
     *
     * @return 纠错等级L/M/Q/H枚举类型的值
     */
    public String getErrorCorrectionLevelVal() {
        if (this.errorCorrectionLevel == ErrorCorrectionLevel.L) {
            return "L";
        } else if (this.errorCorrectionLevel == ErrorCorrectionLevel.M) {
            return "M";
        } else if (this.errorCorrectionLevel == ErrorCorrectionLevel.Q) {
            return "Q";
        } else {
            return "H";
        }
    }

    /**
     * 设置纠错等级L/M/Q/H,纠错等级越高越不易识别，默认设置等级为最高等级H，需要设置枚举类型。
     *
     * @param errorCorrectionLevel 纠错等级
     */
    public void setErrorCorrectionLevel(ErrorCorrectionLevel errorCorrectionLevel) {
        this.errorCorrectionLevel = errorCorrectionLevel;
    }

    /**
     * 设置纠错等级L/M/Q/H,纠错等级越高越不易识别，默认设置等级为最高等级H，可直接设置L/M/Q/H。
     *
     * @param level 纠错等级
     */
    public void setErrorCorrectionLevel(String level) {
        if (StringUtils.equalsByTrimIgnoreCase(level,"L")) {
            this.errorCorrectionLevel = ErrorCorrectionLevel.L;
        } else if (StringUtils.equalsByTrimIgnoreCase(level,"M")) {
            this.errorCorrectionLevel = ErrorCorrectionLevel.M;
        } else if (StringUtils.equalsByTrimIgnoreCase(level,"Q")) {
            this.errorCorrectionLevel = ErrorCorrectionLevel.Q;
        } else {
            this.errorCorrectionLevel = ErrorCorrectionLevel.H;
        }
    }

    /**
     * 获得四周空白处的大小。
     *
     * @return 四周空白处的大小
     */
    public Integer getMargin() {
        return margin;
    }

    /**
     * 设置四周空白处的大小。
     *
     * @param margin 四周空白处的大小
     */
    public void setMargin(Integer margin) {
        this.margin = margin;
    }

    /**
     * 创建二维码图片。
     *
     * @throws Exception 二维码创建异常
     * @return 二维码图片字节数组
     */
    public byte[] create() throws Exception {
        ImgService imgService = ImgService.getInstance();
        return imgService.buildQRcode(this);
    }

    /**
     * 根据文件路径解析二维码图片中的链接地址。
     *
     * @param path 二维码图片文件路径
     * @throws Exception 二维码图片中的链接地址解析异常
     * @return 二维码图片中的链接地址
     */
    public static String decode(String path) throws Exception {
        return decode(new File(path));
    }

    /**
     * 根据文件解析二维码图片中的链接地址。
     *
     * @param file 二维码图片文件
     * @throws Exception 二维码图片中的链接地址解析异常
     * @return 二维码图片中的链接地址
     */
    public static String decode(File file) throws Exception {
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        ImgService imgService = ImgService.getInstance();

        return imgService.decodeQRcode(file);
    }
}
